package com.gitee.fanx.notes.common;

import com.gitee.fanx.notes.common.exception.ResourcesNotFoundException;
import com.gitee.fanx.notes.common.exception.ServiceException;
import org.springframework.dao.DataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.sql.SQLException;
import java.util.stream.Collectors;

/**
 * 统一异常处理 对于业务异常：返回头 Http 状态码一律使用500，避免浏览器缓存，在响应 Result 中指明异常的状态码 code
 *
 * @author fanx
 */
@RestControllerAdvice
public class ExceptionResolver {

	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	@ExceptionHandler(ConstraintViolationException.class)
	public WebResult<?> validatorException(final ConstraintViolationException e) {
		final String msg = e.getConstraintViolations().stream().map(ConstraintViolation::getMessage)
				.collect(Collectors.joining(","));
		// e.toString 多了不需要用户知道的属性路径
		e.printStackTrace();
		return WebResult.fail(ResultCode.VIOLATION_EXCEPTION.getValue(), msg);
	}

	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	@ExceptionHandler({ ServiceException.class })
	public WebResult<?> serviceException(final ServiceException e) {
		e.printStackTrace();
		return WebResult.fail(e.getResultCode().getValue(), e.getMessage());
	}

	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	@ExceptionHandler({ ResourcesNotFoundException.class })
	public WebResult<?> resourcesException(final Throwable e) {
		e.printStackTrace();
		return WebResult.fail(ResultCode.FIND_FAILED);
	}

	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	@ExceptionHandler({ SQLException.class, DataAccessException.class })
	public WebResult<?> databaseException(final Throwable e) {
		e.printStackTrace();
		return WebResult.fail(ResultCode.DATABASE_EXCEPTION);
	}

	@ResponseStatus(HttpStatus.NOT_FOUND)
	@ExceptionHandler(NoHandlerFoundException.class)
	public WebResult<?> apiNotFoundException(final Throwable e, final HttpServletRequest request) {
		e.printStackTrace();
		return WebResult.fail("API [" + getMappingUrl(request) + "] not existed");
	}

	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	@ExceptionHandler(Exception.class)
	public WebResult<?> globalException(final HttpServletRequest request, final Throwable e) {
		e.printStackTrace();
		return WebResult.fail(HttpStatus.INTERNAL_SERVER_ERROR.value(),
				String.format("%s => %s", getMappingUrl(request), e.getMessage()));
	}

	private String getMappingUrl(final HttpServletRequest request) {
		return request.getRequestURI().substring(request.getContextPath().length());
	}

}
